#nullable enable
using Godot;
using System.Collections.Generic;

namespace AndroidUnevenRoadGame.Game
{
    /// <summary>
    /// 随机事件系统：负责生成事件、应用选项影响并驱动 UI。
    /// </summary>
    public sealed class EventManager
    {
        private readonly GameRoot _game;
        private readonly List<EventDefinition> _events = new();
        private bool _isLoaded;
        public EventDefinition? CurrentEvent { get; private set; }

        public EventManager(GameRoot game)
        {
            _game = game;
        }

        public EventDefinition GenerateRandomEvent()
        {
            EnsureLoaded();
            if (_events.Count == 0)
            {
                GD.PushWarning("没有可用的事件定义");
                CurrentEvent = EventDefinition.CreateDefault();
                return CurrentEvent;
            }

            var index = _game.Random.RandiRange(0, _events.Count - 1);
            CurrentEvent = _events[index];
            return CurrentEvent;
        }

        public void ApplyEventOption(EventDefinition eventDefinition, EventOption option)
        {
            foreach (var effect in option.Effects)
            {
                switch (effect.Type)
                {
                    case EventEffectType.Gold:
                        _game.AwardGold(effect.Value);
                        break;
                    case EventEffectType.Heal:
                        _game.Player.Heal(effect.Value);
                        break;
                    case EventEffectType.TakeDamage:
                        _game.Player.TakeDamage(effect.Value);
                        break;
                }
            }

            GD.Print($"事件 {eventDefinition.Id} 选择：{option.Id}");
            CurrentEvent = null;
        }

        private void EnsureLoaded()
        {
            if (_isLoaded)
            {
                return;
            }

            var resourcePath = "res://Resources/Events/events.json";
            var file = FileAccess.Open(resourcePath, FileAccess.ModeFlags.Read);
            if (file == null)
            {
                GD.PushWarning($"未找到事件配置：{resourcePath}");
                _isLoaded = true;
                return;
            }

            var jsonText = file.GetAsText();
            file.Dispose();

            var result = Json.ParseString(jsonText);
            if (result.VariantType != Variant.Type.Array)
            {
                GD.PushWarning("事件配置格式错误：根节点需要为数组");
                _isLoaded = true;
                return;
            }

            foreach (Variant entryVar in result.AsGodotArray())
            {
                if (entryVar.VariantType != Variant.Type.Dictionary)
                {
                    continue;
                }

                var dict = entryVar.AsGodotDictionary();
                var options = new List<EventOption>();
                if (dict.TryGetValue("options", out var optionsVar) &&
                    optionsVar.VariantType == Variant.Type.Array)
                {
                    foreach (Variant optionVar in optionsVar.AsGodotArray())
                    {
                        if (optionVar.VariantType != Variant.Type.Dictionary)
                        {
                            continue;
                        }

                        var optionDict = optionVar.AsGodotDictionary();
                        var effects = new List<EventEffect>();
                        if (optionDict.TryGetValue("effects", out var effectsVar) &&
                            effectsVar.VariantType == Variant.Type.Array)
                        {
                            foreach (Variant effectVar in effectsVar.AsGodotArray())
                            {
                                if (effectVar.VariantType != Variant.Type.Dictionary)
                                {
                                    continue;
                                }

                                var effectDict = effectVar.AsGodotDictionary();
                                effects.Add(new EventEffect(
                                    ParseEffectType(effectDict.TryGetValue("type", out var typeVar) && typeVar.VariantType == Variant.Type.String ? typeVar.AsString() : "Gold"),
                                    effectDict.TryGetValue("value", out var valueVar) && valueVar.VariantType == Variant.Type.Int ? valueVar.AsInt32() : 0
                                ));
                            }
                        }

                        options.Add(new EventOption(
                            optionDict.TryGetValue("id", out var optionIdVar) && optionIdVar.VariantType == Variant.Type.String ? optionIdVar.AsString() : "option",
                            optionDict.TryGetValue("description", out var descVar) && descVar.VariantType == Variant.Type.String ? descVar.AsString() : string.Empty,
                            effects
                        ));
                    }
                }

                _events.Add(new EventDefinition(
                    dict.TryGetValue("id", out var idVar) && idVar.VariantType == Variant.Type.String ? idVar.AsString() : "event",
                    dict.TryGetValue("title", out var titleVar) && titleVar.VariantType == Variant.Type.String ? titleVar.AsString() : string.Empty,
                    dict.TryGetValue("description", out var descriptionVar) && descriptionVar.VariantType == Variant.Type.String ? descriptionVar.AsString() : string.Empty,
                    options
                ));
            }

            _isLoaded = true;
        }

        private static EventEffectType ParseEffectType(string type)
        {
            return type switch
            {
                "Heal" => EventEffectType.Heal,
                "TakeDamage" => EventEffectType.TakeDamage,
                _ => EventEffectType.Gold
            };
        }
    }

    public sealed record EventDefinition(string Id, string Title, string Description, IReadOnlyList<EventOption> Options)
    {
        public static EventDefinition CreateDefault()
        {
            return new EventDefinition(
                "default",
                "未知事件",
                "暂无事件描述",
                new List<EventOption>
                {
                    new EventOption("ok", "离开", new List<EventEffect>())
                });
        }
    }

    public sealed record EventOption(string Id, string Description, IReadOnlyList<EventEffect> Effects);

    public sealed record EventEffect(EventEffectType Type, int Value);

    public enum EventEffectType
    {
        Gold,
        Heal,
        TakeDamage
    }
}

